/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_MOTINOVA_CAN.c
** 模块名称： 天腾CAN协议处理模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
**           V1.1     蒲磊       2023.03.02   3档的时候，挡位数值发送4.赵华军反馈助力不强，要求3档发4
**           V1.2     蒲磊       2023.04.03   1-4档按照实际发，5档为智能模式，发0x33
**                                            增加了关机报文的发送
**                                            修改了大灯报文发送错误的Bug。应该发F0，F1，实际发0，1
**                                            修改了关机报文的发送方式。关机函数里面只置位标志，在协议轮询函数里面发送具体的报文
**           V1.3     蒲磊       2023.04.04   1.增加了在退出设置时，更新自动关机时间（同步发送给控制器）
**                                            2.修改了仪表发送给控制的0x3408命令，预留6字节，实际留4字节的Bug。
**           V1.4     蒲磊       2023.04.07   1.仪表发送给控制器的0x3408命令，重新改回预留4字节。（天腾技术人员要求并确认）
**                                            2.退出设置时，发送的设置帧（0x3408命令）发送3次。防止控制器收不到
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include <string.h>
#include "Config.h"
#include "App_Protocol.h"
#include "App_MainTask.h"
#include "App_Parameter.h"
#include "multi_cyc_fifo.h"
#include "bsp.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/

/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/
static void vCAN_Receive_MCU_Message_710(can_rx_message_type *pCanMsg,strBikeInfo *pBikeInfo);
static void vCAN_Receive_MCU_Message_713(can_rx_message_type *pCanMsg,strBikeInfo *pBikeInfo);
static void vCAN_Receive_BMS_Message_720(can_rx_message_type *pCanMsg,strBikeInfo *pBikeInfo);

static void vCan_Send_DisplayMessage(uint32_t ID,uint16_t Cmd,strBikeInfo   *pBikeInfo);
static void vPROTOCOL_Factory_Response(uint32_t Cmd,uint16_t Data);
static uint32_t CRC32_Calculate( uint8_t *pData, uint16_t Length );
/******************************************************************************
* 全局变量定义
******************************************************************************/
strBikeInfo     gxBikeInfo = {0};         /*车辆数据*/

static uint32_t gulCommunicationCnt = 0;
static uint32_t gulMCU_ErrorCodeCnt = 0;            /*MCU错误代码发送超时计数变量*/
static uint32_t gulBMS_ErrorCodeCnt = 0;            /*BMS错误代码发送超时计数变量*/
static uint8_t  gucRequestPowerOff  = 0;            /*请求关机标志*/
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/

/******************************************************************************
** 功  能：CAN协议初始化函数
** 参  数：无
** 返回值：无
** 备  注：用于初始化CAN协议模块的相关变量，同时创建收发队列。
******************************************************************************/
void vPROTOCOL_Init(void)
{
    muilt_cyc_fifo_error_code_t    lxState;
    MCF_ApplyFifo(gxCAN_RxQueue_Len,gxCAN_RxQueue,&lxState);     /*初始化接收队列*/
    MCF_ApplyFifo(gxCAN_TxQueue_Len,gxCAN_TxQueue,&lxState);     /*初始化发送队列*/
    gxBikeInfo.Battery.Soc = -1;
    gxBikeInfo.MCU.Soc     = -1;
}

/******************************************************************************
** 功  能：CRC32校验函数
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
static uint32_t CRC32_Calculate( uint8_t *pData, uint16_t Length )
{
    const uint32_t Crc32Table[ 256 ] = {
        0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
        0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
        0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
        0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
        0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
        0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
        0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
        0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
        0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
        0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
        0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
        0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
        0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
        0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
        0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
        0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
        0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
        0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
        0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
        0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
        0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
        0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
        0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
        0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
        0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
        0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
        0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
        0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
        0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
        0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
        0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
        0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
        0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
        0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
        0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
        0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
        0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
        0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
        0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
        0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
        0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
        0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
        0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
    };

    uint32_t nReg;
    uint32_t nTemp = 0;
    uint16_t i, n;
    nReg = 0xFFFFFFFF;
    for ( n = 0; n < Length; n++ )
    {
        nReg ^= (uint32_t) pData[ n ];
        for ( i = 0; i < 4; i++ )
        {
            nTemp = Crc32Table[ ( uint8_t )( ( nReg >> 24 ) & 0xFF ) ];
            nReg <<= 8;
            nReg ^= nTemp;
        }
    }
    return nReg;
}



/******************************************************************************
** 功  能：将接收到的Can帧解析为用户的Can数据结构
** 参  数：pCanMessage-接收到的Can数据结构体指针
** 返回值：无
** 备  注：该函数是整个Can协议模块的入口函数。当CAN总线接收一帧Can数据后，调用该函数，
**        将Can消息帧转换为用户的CAN数据格式，并且放入接收队列
******************************************************************************/
void vCAN_CanMsgToUserMsg(can_rx_message_type *pCanMessage)
{
    muilt_cyc_fifo_error_code_t lxState;

    /*天腾CAN不需要转换格式，直接放入FIFO队列*/
    MCF_WriteDataInFifo(gxCAN_RxQueue,(uint8_t *)pCanMessage,sizeof(can_rx_message_type),&lxState);
}




/******************************************************************************
** 功  能：CAN协议轮询，处理收发
** 参  数：无
** 返回值：无
** 备  注：该函数是模块主函数，应定时调用，调用周期一般10-20ms，定时处理收发
******************************************************************************/
void vPROTOCOL_Loop(void)
{
    static uint32_t lulTicks = 0;
    can_tx_message_type    lxCanTxMessage;
    can_rx_message_type    lxCanRxMessage;

    muilt_cyc_fifo_error_code_t lxState;
    uint16_t lxFifoCanReadLen;
    uint16_t lxActualReadLen;

    /*接收到控制开机信号后，200ms发送一次的帧*/
    if(lulTicks % (200 / CAN_LOOP_CYCLE) == 0)
    {
        vCan_Send_DisplayMessage(0x0731,0x3002,&gxBikeInfo);
        if(gucRequestPowerOff)
        {
            vCan_Send_DisplayMessage(0x0730,0x1008,&gxBikeInfo);
        }
    }

    /*1000钟发送一次的*/
    if(lulTicks % (1000 / CAN_LOOP_CYCLE) == 0)
    {
        vCan_Send_DisplayMessage(0x0731,0x3500,&gxBikeInfo);
        vCan_Send_DisplayMessage(0x0731,0x3300,&gxBikeInfo);
    }

    lulTicks++;
    gulCommunicationCnt++;

    /*3秒钟，没有接受到MCU和BMS的错误代码，认为无错误。错误代码置0*/
    if(++gulMCU_ErrorCodeCnt > 3000 / CAN_LOOP_CYCLE)
    {
        gxBikeInfo.MCU.ErrorCode = 0;
    }
    if(++gulBMS_ErrorCodeCnt > 3000 / CAN_LOOP_CYCLE)
    {
        gxBikeInfo.Battery.ErrorCode = 0;
    }

    /*10S之内，通信超时变量未复位，报70错误*/
    if(gulCommunicationCnt > (10000 / CAN_LOOP_CYCLE))
    {
        gxBikeInfo.ErrCode = 70;
        gxBikeInfo.MCU.Speed = 0;   /*报70错误时，强制把速度变为0*/
    }
    else
    {
        if(gxBikeInfo.ErrCode == 70)
        {
            gxBikeInfo.ErrCode = 0;
        }
    }

    /*判断接收队列是否非空*/
    MCF_GetCanReadLen(gxCAN_RxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_RxQueue,sizeof(can_rx_message_type),(uint8_t *)&lxCanRxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(can_rx_message_type) && lxState == kMultiCycFiFo_Error_NONE)
        {
            switch(lxCanRxMessage.standard_id)
            {
            case 0x710:
            {
                gulCommunicationCnt = 0;        /*复位通信超时计数*/
                vCAN_Receive_MCU_Message_710(&lxCanRxMessage,&gxBikeInfo);
                break;
            }
            case 0x713:
            {
                vCAN_Receive_MCU_Message_713(&lxCanRxMessage,&gxBikeInfo);
                break;
            }
            case 0x720:
            {
                vCAN_Receive_BMS_Message_720(&lxCanRxMessage,&gxBikeInfo);
                break;
            }
            }
        }
    }

    /*判断发送缓冲区是否有数据需要发送*/
    MCF_GetCanReadLen(gxCAN_TxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_TxQueue,sizeof(can_tx_message_type),(uint8_t *)&lxCanTxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(can_tx_message_type) && lxState == kMultiCycFiFo_Error_NONE)
        {
            /*调用发送函数进行发送*/
            can_message_transmit(CAN1,&lxCanTxMessage);
        }
    }
}

/******************************************************************************
** 功  能：接收处理控制器发送的，ID为0x710的消息
** 参  数：pRxMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Receive_MCU_Message_710(can_rx_message_type *pRxMsg,strBikeInfo *pBikeInfo)
{
    static uint8_t lucStartFrame = 0;   /*开始一帧的接收标志*/
    static uint8_t lucBuffer[80];       /*帧数据缓存*/
    static uint8_t lucPackNums = 0;     /*该帧已接收到的字节数*/
    uint32_t   lulChecksum,lulGetChecksum;

    if(pRxMsg->data[0] == 0x55 && pRxMsg->data[1] == 0xAA)
    {
        lucStartFrame = 1;
        memset(lucBuffer,0,80);     /*清零缓存*/
        /*填充帧头和ID，用于校验*/
        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x07;
        lucBuffer[3] = 0x10;
        memcpy(lucBuffer + 4,&(pRxMsg->data[2]),pRxMsg->dlc - 2);     /*接收到的数据拷贝到缓冲区*/
        lucPackNums += (pRxMsg->dlc + 2);   /*把ID的长度也算进去*/
    }
    else
    {
        /*已经开始了一帧的接收*/
        if(lucStartFrame == 1)
        {
            memcpy(lucBuffer + lucPackNums,pRxMsg->data,pRxMsg->dlc);   /*该包接收的数据拷贝到缓冲区*/
            lucPackNums += pRxMsg->dlc;
            /*判断接收到的包长度和协议包长度是否一致，并判断帧尾是否是0xF0*/
            if((lucBuffer[5] + 9 == lucPackNums - 2) && lucBuffer[lucBuffer[5] + 10] == 0xF0)
            {
                /*长度正确，帧尾正确，认为一帧接收完成*/
                lucStartFrame = 0;
                lucPackNums = 0;
                /*计算校验值，并和接收到的校验值进行比较*/
                lulGetChecksum = ((uint32_t)lucBuffer[lucBuffer[5] + 6] << 24) | ((uint32_t)lucBuffer[lucBuffer[5] + 7] << 16) | ((uint32_t)lucBuffer[lucBuffer[5] + 8] << 8) | ((uint32_t)lucBuffer[lucBuffer[5] + 9]);
                lulChecksum    = CRC32_Calculate(lucBuffer,lucBuffer[5] + 6);
                if(lulChecksum == lulGetChecksum)
                {
                    /*根据命令字进行解析*/
                    switch(((uint16_t)lucBuffer[6] << 8) | lucBuffer[7])
                    {
                    case 0x1020:
                    {
                        pBikeInfo->MCU.Speed   = (uint16_t)(lucBuffer[9] << 8) | lucBuffer[8];        /*车速，0.1km/h*/
                        pBikeInfo->MCU.Rpm     = (uint16_t)(lucBuffer[11] << 8) | lucBuffer[10];      /*输出转速，1rpm*/
                        pBikeInfo->MCU.Power   = (uint16_t)(lucBuffer[13] << 8) | lucBuffer[12];      /*电功率，W*/
                        pBikeInfo->MCU.Voltage = (uint16_t)(lucBuffer[15] << 8) | lucBuffer[14];      /*电压，mv*/
                        pBikeInfo->MCU.Current = (uint16_t)(lucBuffer[17] << 8) | lucBuffer[16];      /*电流，mA*/
                        pBikeInfo->MCU.Cadence = lucBuffer[18];                                       /*踏频*/
                        pBikeInfo->MCU.Torque  = lucBuffer[19];                                       /*力矩*/
                        pBikeInfo->MCU.TorqueDir = lucBuffer[20];                                     /*力矩方向*/
                        pBikeInfo->MCU.Pas     = lucBuffer[21];                                       /*挡位*/
                        pBikeInfo->MCU.Lamp    = lucBuffer[22];                                       /*大灯状态*/
                        pBikeInfo->MCU.Soc     = lucBuffer[23];                                       /*剩余电量*/
                        pBikeInfo->MCU.Range   = ((uint16_t)lucBuffer[25] << 8) | lucBuffer[24];      /*剩余里程*/
                        pBikeInfo->MCU.Power_Avg = lucBuffer[28];                                     /*平均功耗*/
                        pBikeInfo->MCU.Temp_PCB  = lucBuffer[29];                                     /*PCB温度*/
                        pBikeInfo->MCU.Temp_MOTOR = lucBuffer[30];                                    /*电机绕组温度*/
                        pBikeInfo->MCU.Temp_MCU   = lucBuffer[31];                                    /*MCU温度*/
                        pBikeInfo->MCU.Trip_WhenStart = ((uint16_t)lucBuffer[33] << 8) | lucBuffer[32]; /*开机后骑行里程*/
                        pBikeInfo->MCU.Time_WhenStart = ((uint16_t)lucBuffer[35] << 8) | lucBuffer[34]; /*开机后骑行时间*/
                        break;
                    }
                    case 0x1104:
                    {
                        /*一旦接收到错误代码，复位错误代码计数变量*/
                        gulMCU_ErrorCodeCnt = 0;
                        pBikeInfo->MCU.ErrorCode = ((uint32_t)lucBuffer[11] << 24) | ((uint32_t)lucBuffer[10] << 16) | ((uint32_t)lucBuffer[9] << 8) | ((uint32_t)lucBuffer[8]);
                        break;
                    }
                    case 0x1240:
                    {
                        memcpy(pBikeInfo->MCU.Info_Mode,&lucBuffer[8],16);   /*电机Mode字符，最大16字节*/
                        memcpy(pBikeInfo->MCU.Info_SN,&lucBuffer[24],16);    /*电机SN字符，最大16字节*/
                        memcpy(pBikeInfo->MCU.Info_HW,&lucBuffer[40],16);    /*电机HW字符，最大16字节*/
                        memcpy(pBikeInfo->MCU.Info_FW,&lucBuffer[56],16);    /*电机FW字符，最大16字节*/
                        break;
                    }
                    case 0x1510:
                    {
                        pBikeInfo->MCU.ODO       = ((uint32_t)lucBuffer[11] << 24) | ((uint32_t)lucBuffer[10] << 16) | ((uint32_t)lucBuffer[9] << 8) | ((uint32_t)lucBuffer[8]);
                        pBikeInfo->MCU.ODO_Time  = ((uint32_t)lucBuffer[15] << 24) | ((uint32_t)lucBuffer[14] << 16) | ((uint32_t)lucBuffer[13] << 8) | ((uint32_t)lucBuffer[12]);
                        pBikeInfo->MCU.Trip      = ((uint32_t)lucBuffer[19] << 24) | ((uint32_t)lucBuffer[18] << 16) | ((uint32_t)lucBuffer[17] << 8) | ((uint32_t)lucBuffer[16]);
                        pBikeInfo->MCU.Trip_Time = ((uint32_t)lucBuffer[23] << 24) | ((uint32_t)lucBuffer[22] << 16) | ((uint32_t)lucBuffer[21] << 8) | ((uint32_t)lucBuffer[20]);
                        break;
                    }
                    }
                }
            }
        }
        else
        {
            /*未开始接收时，收到非起始包，丢弃，复位相关变量*/
            lucStartFrame = 0;
            lucPackNums   = 0;
        }

    }

}

/******************************************************************************
** 功  能：接收处理控制器发送的，ID为0x713的消息
** 参  数：pRxMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Receive_MCU_Message_713(can_rx_message_type *pRxMsg,strBikeInfo *pBikeInfo)
{
    static uint8_t lucStartFrame = 0;   /*开始一帧的接收标志*/
    static uint8_t lucBuffer[80];       /*帧数据缓存*/
    static uint8_t lucPackNums = 0;     /*该帧已接收到的字节数*/
    uint32_t   lulChecksum,lulGetChecksum;

    if(pRxMsg->data[0] == 0x55 && pRxMsg->data[1] == 0xAA)
    {
        lucStartFrame = 1;
        memset(lucBuffer,0,80);     /*清零缓存*/
        /*填充帧头和ID，用于校验*/
        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x07;
        lucBuffer[3] = 0x13;
        memcpy(lucBuffer + 4,&(pRxMsg->data[2]),pRxMsg->dlc - 2);     /*接收到的数据拷贝到缓冲区*/
        lucPackNums += (pRxMsg->dlc + 2);   /*把ID的长度也算进去*/
    }
    else
    {
        /*已经开始了一帧的接收*/
        if(lucStartFrame == 1)
        {
            memcpy(lucBuffer + lucPackNums,pRxMsg->data,pRxMsg->dlc);   /*该包接收的数据拷贝到缓冲区*/
            lucPackNums += pRxMsg->dlc;
            /*判断接收到的包长度和协议包长度是否一致，并判断帧尾是否是0xF0*/
            if((lucBuffer[5] + 9 == lucPackNums - 2) && lucBuffer[lucBuffer[5] + 10] == 0xF0)
            {
                /*长度正确，帧尾正确，认为一帧接收完成*/
                lucStartFrame = 0;
                lucPackNums = 0;
                /*计算校验值，并和接收到的校验值进行比较*/
                lulGetChecksum = ((uint32_t)lucBuffer[lucBuffer[5] + 6] << 24) | ((uint32_t)lucBuffer[lucBuffer[5] + 7] << 16) | ((uint32_t)lucBuffer[lucBuffer[5] + 8] << 8) | ((uint32_t)lucBuffer[lucBuffer[5] + 9]);
                lulChecksum    = CRC32_Calculate(lucBuffer,lucBuffer[5] + 6);
                if(lulChecksum == lulGetChecksum)
                {
                    /*根据命令字进行解析*/
                    switch(((uint16_t)lucBuffer[6] << 8) | lucBuffer[7])
                    {
                    case 0x5408:
                    {
                        pBikeInfo->MCU.WheelLength_Base   = lucBuffer[8];               /*轮周长基准值*/
                        pBikeInfo->MCU.StartType          = lucBuffer[9];               /*启动模式*/
                        pBikeInfo->MCU.SpeedLimit         = lucBuffer[10];              /*限速*/
                        pBikeInfo->MCU.WheelLength_Adjust = (int8_t)lucBuffer[11];      /*轮周长调整值*/
                        pBikeInfo->MCU.AssistType         = lucBuffer[12];              /*助力方案*/
                        pBikeInfo->MCU.IdleTime           = lucBuffer[13];              /*自动关机时间*/
                        break;
                    }

                    }
                }
            }
        }
        else
        {
            /*未开始接收时，收到非起始包，丢弃，复位相关变量*/
            lucStartFrame = 0;
            lucPackNums   = 0;
        }

    }


}

/******************************************************************************
** 功  能：接收处理BMS发送的ID为0x720的消息
** 参  数：pRxMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Receive_BMS_Message_720(can_rx_message_type *pRxMsg,strBikeInfo *pBikeInfo)
{
    static uint8_t lucStartFrame = 0;   /*开始一帧的接收标志*/
    static uint8_t lucBuffer[80];       /*帧数据缓存*/
    static uint8_t lucPackNums = 0;     /*该帧已接收到的字节数*/
    uint32_t   lulChecksum,lulGetChecksum;
    uint8_t n;

    if(pRxMsg->data[0] == 0x55 && pRxMsg->data[1] == 0xAA)
    {
        lucStartFrame = 1;
        memset(lucBuffer,0,80);     /*清零缓存*/
        /*填充帧头和ID，用于校验*/
        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x07;
        lucBuffer[3] = 0x20;
        memcpy(lucBuffer + 4,&(pRxMsg->data[2]),pRxMsg->dlc - 2);     /*接收到的数据拷贝到缓冲区*/
        lucPackNums += (pRxMsg->dlc + 2);   /*把ID的长度也算进去*/
    }
    else
    {
        /*已经开始了一帧的接收*/
        if(lucStartFrame == 1)
        {
            memcpy(lucBuffer + lucPackNums,pRxMsg->data,pRxMsg->dlc);   /*该包接收的数据拷贝到缓冲区*/
            lucPackNums += pRxMsg->dlc;
            /*判断接收到的包长度和协议包长度是否一致，并判断帧尾是否是0xF0*/
            if((lucBuffer[5] + 9 == lucPackNums - 2) && lucBuffer[lucBuffer[5] + 10] == 0xF0)
            {
                /*长度正确，帧尾正确，认为一帧接收完成*/
                lucStartFrame = 0;
                lucPackNums = 0;
                /*计算校验值，并和接收到的校验值进行比较*/
                lulGetChecksum = ((uint32_t)lucBuffer[lucBuffer[5] + 6] << 24) | ((uint32_t)lucBuffer[lucBuffer[5] + 7] << 16) | ((uint32_t)lucBuffer[lucBuffer[5] + 8] << 8) | ((uint32_t)lucBuffer[lucBuffer[5] + 9]);
                lulChecksum    = CRC32_Calculate(lucBuffer,lucBuffer[5] + 6);
                if(lulChecksum == lulGetChecksum)
                {
                    /*根据命令字进行解析*/
                    switch(((uint16_t)lucBuffer[6] << 8) | lucBuffer[7])
                    {
                    case 0x1010:
                    {
                        pBikeInfo->Battery.Voltage  = ((uint16_t)lucBuffer[9] << 8) | lucBuffer[8];         /*电压，mv*/
                        pBikeInfo->Battery.Current  = ((int16_t)lucBuffer[11] << 8) | lucBuffer[10];        /*电流，mA，充电正，放电负*/
                        pBikeInfo->Battery.ResCap   = ((uint16_t)lucBuffer[13] << 8) | lucBuffer[12];       /*剩余容量，mah*/
                        pBikeInfo->Battery.FullCap  = ((uint16_t)lucBuffer[15] << 8) | lucBuffer[14];       /*满容量，mah*/
                        pBikeInfo->Battery.Temp     = lucBuffer[16];                                        /*电芯温度*/
                        pBikeInfo->Battery.Soc      = lucBuffer[17];                                        /*剩余电量*/
                        pBikeInfo->Battery.State    = lucBuffer[18];                                        /*运行状态*/
                        pBikeInfo->Battery.Soh      = lucBuffer[19];                                        /*健康状态SOH*/
                        break;
                    }
                    case 0x1120:
                    {
                        for(n = 0; n < 16; n++)
                        {
                            pBikeInfo->Battery.CellVoltage[n] = ((uint16_t)lucBuffer[9 + 2 * n]) | lucBuffer[8 + 2 * n];    /*电芯电压,mv*/
                        }
                        break;
                    }
                    case 0x1204:
                    {
                        /*一旦接收到错误代码，复位错误代码计数变量*/
                        gulBMS_ErrorCodeCnt = 0;
                        pBikeInfo->Battery.ErrorCode = ((uint32_t)lucBuffer[11] << 24) | ((uint32_t)lucBuffer[10] << 16) | ((uint32_t)lucBuffer[9] << 8) | ((uint32_t)lucBuffer[8]);
                        break;
                    }
                    case 0x1540:
                    {
                        memcpy(pBikeInfo->Battery.Info_Mode,&lucBuffer[8],16);   /*电机Mode字符，最大16字节*/
                        memcpy(pBikeInfo->Battery.Info_SN,&lucBuffer[24],16);    /*电机SN字符，最大16字节*/
                        memcpy(pBikeInfo->Battery.Info_HW,&lucBuffer[40],16);    /*电机HW字符，最大16字节*/
                        memcpy(pBikeInfo->Battery.Info_FW,&lucBuffer[56],16);    /*电机FW字符，最大16字节*/
                        break;
                    }
                    }
                }
            }
        }
        else
        {
            /*未开始接收时，收到非起始包，丢弃，复位相关变量*/
            lucStartFrame = 0;
            lucPackNums   = 0;
        }

    }
}

/******************************************************************************
** 功  能：仪表发送消息
** 参  数：ID-要发送的帧ID号，Cmd-要发送的指令，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCan_Send_DisplayMessage(uint32_t ID,uint16_t Cmd,strBikeInfo   *pBikeInfo)
{
    static uint8_t                  lucBuffer[80];
    uint8_t                         lucBuffer_Crc[80];
    can_tx_message_type             lxCanTxData;
    muilt_cyc_fifo_error_code_t     lxState;
    uint32_t                        lulCRC;
    uint8_t                         n;

    switch(Cmd)
    {
    case 0x3002:
    {
        memset(lucBuffer,0,80);
        memset(lucBuffer_Crc,0,80);

        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x0C;                /*广播式发送*/
        lucBuffer[3] = 4;                   /*命令段总长度4*/
        lucBuffer[4] = 0x30;
        lucBuffer[5] = 0x02;                /*命令字0x3002*/
        lucBuffer[6] = pBikeInfo->Display.Pas;      /*挡位*/
        lucBuffer[7] = pBikeInfo->Display.Lamp;     /*大灯状态*/

        lucBuffer_Crc[0]     = 0x55;
        lucBuffer_Crc[1]     = 0xAA;
        lucBuffer_Crc[2]     = 0x07;
        lucBuffer_Crc[3]     = 0x31;
        memcpy(lucBuffer_Crc + 4,lucBuffer + 2,6);
        lulCRC = CRC32_Calculate(lucBuffer_Crc,10);

        lucBuffer[8]      = lulCRC >> 24;
        lucBuffer[9]      = lulCRC >> 16;
        lucBuffer[10]     = lulCRC >> 8;
        lucBuffer[11]     = lulCRC;
        lucBuffer[12]     = 0xF0;

        for(n = 0; n < 2; n++)
        {
            lxCanTxData.id_type     = CAN_ID_STANDARD;
            lxCanTxData.frame_type  = CAN_TFT_DATA;
            lxCanTxData.standard_id = 0x731;
            if(n < 1)
            {
                lxCanTxData.dlc     = 8;
            }
            else
            {
                lxCanTxData.dlc     = 5;
            }
            lxCanTxData.data[0]     = lucBuffer[n * 8 + 0];
            lxCanTxData.data[1]     = lucBuffer[n * 8 + 1];
            lxCanTxData.data[2]     = lucBuffer[n * 8 + 2];
            lxCanTxData.data[3]     = lucBuffer[n * 8 + 3];
            lxCanTxData.data[4]     = lucBuffer[n * 8 + 4];
            lxCanTxData.data[5]     = lucBuffer[n * 8 + 5];
            lxCanTxData.data[6]     = lucBuffer[n * 8 + 6];
            lxCanTxData.data[7]     = lucBuffer[n * 8 + 7];
            /*放入队列*/
            MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxData,sizeof(can_tx_message_type),&lxState);
        }
        break;
    }
    case 0x3300:
    {
        memset(lucBuffer,0,80);
        memset(lucBuffer_Crc,0,80);

        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x11;                /*读命令*/
        lucBuffer[3] = 2;                   /*命令段总长度2*/
        lucBuffer[4] = 0x33;
        lucBuffer[5] = 0x00;                /*命令字0x3300*/


        lucBuffer_Crc[0]     = 0x55;
        lucBuffer_Crc[1]     = 0xAA;
        lucBuffer_Crc[2]     = 0x07;
        lucBuffer_Crc[3]     = 0x31;
        memcpy(lucBuffer_Crc + 4,lucBuffer + 2,4);
        lulCRC = CRC32_Calculate(lucBuffer_Crc,8);

        lucBuffer[6]      = lulCRC >> 24;
        lucBuffer[7]      = lulCRC >> 16;
        lucBuffer[8]      = lulCRC >> 8;
        lucBuffer[9]      = lulCRC;
        lucBuffer[10]     = 0xF0;

        for(n = 0; n < 2; n++)
        {
            lxCanTxData.id_type     = CAN_ID_STANDARD;
            lxCanTxData.frame_type  = CAN_TFT_DATA;
            lxCanTxData.standard_id = 0x731;
            if(n < 1)
            {
                lxCanTxData.dlc     = 8;
            }
            else
            {
                lxCanTxData.dlc     = 3;
            }
            lxCanTxData.data[0]     = lucBuffer[n * 8 + 0];
            lxCanTxData.data[1]     = lucBuffer[n * 8 + 1];
            lxCanTxData.data[2]     = lucBuffer[n * 8 + 2];
            lxCanTxData.data[3]     = lucBuffer[n * 8 + 3];
            lxCanTxData.data[4]     = lucBuffer[n * 8 + 4];
            lxCanTxData.data[5]     = lucBuffer[n * 8 + 5];
            lxCanTxData.data[6]     = lucBuffer[n * 8 + 6];
            lxCanTxData.data[7]     = lucBuffer[n * 8 + 7];
            /*放入队列*/
            MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxData,sizeof(can_tx_message_type),&lxState);
        }
        break;
    }
    case 0x3408:
    {
        memset(lucBuffer,0,80);
        memset(lucBuffer_Crc,0,80);

        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x16;                /*写命令*/
        lucBuffer[3] = 10;                  /*命令段总长度12*/
        lucBuffer[4] = 0x34;
        lucBuffer[5] = 0x08;                /*命令字0x3408*/
        lucBuffer[6] = pBikeInfo->Display.WheelLength_Adjust;       /*轮径微调值*/
        lucBuffer[7] = pBikeInfo->Display.StartType;                /*启动模式*/
        lucBuffer[8] = pBikeInfo->Display.AssistType;               /*助力方案*/
        lucBuffer[9] = pBikeInfo->Display.IdleTime;                 /*自动关机时间*/
        lucBuffer[10] = 0;  /*预留4字节，填充0*/
        lucBuffer[11] = 0;
        lucBuffer[12] = 0;
        lucBuffer[13] = 0;


        lucBuffer_Crc[0]     = 0x55;
        lucBuffer_Crc[1]     = 0xAA;
        lucBuffer_Crc[2]     = 0x07;
        lucBuffer_Crc[3]     = 0x31;
        memcpy(lucBuffer_Crc + 4,lucBuffer + 2,12);
        lulCRC = CRC32_Calculate(lucBuffer_Crc,16);

        lucBuffer[14]     = lulCRC >> 24;
        lucBuffer[15]     = lulCRC >> 16;
        lucBuffer[16]     = lulCRC >> 8;
        lucBuffer[17]     = lulCRC;
        lucBuffer[18]     = 0xF0;

        for(n = 0; n < 3; n++)
        {
            lxCanTxData.id_type     = CAN_ID_STANDARD;
            lxCanTxData.frame_type  = CAN_TFT_DATA;
            lxCanTxData.standard_id = 0x731;
            if(n < 2)
            {
                lxCanTxData.dlc     = 8;
            }
            else
            {
                lxCanTxData.dlc     = 3;
            }
            lxCanTxData.data[0]     = lucBuffer[n * 8 + 0];
            lxCanTxData.data[1]     = lucBuffer[n * 8 + 1];
            lxCanTxData.data[2]     = lucBuffer[n * 8 + 2];
            lxCanTxData.data[3]     = lucBuffer[n * 8 + 3];
            lxCanTxData.data[4]     = lucBuffer[n * 8 + 4];
            lxCanTxData.data[5]     = lucBuffer[n * 8 + 5];
            lxCanTxData.data[6]     = lucBuffer[n * 8 + 6];
            lxCanTxData.data[7]     = lucBuffer[n * 8 + 7];
            /*放入队列*/
            MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxData,sizeof(can_tx_message_type),&lxState);
        }
        break;
    }
    case 0x3500:
    {
        memset(lucBuffer,0,80);
        memset(lucBuffer_Crc,0,80);

        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x11;                /*读命令*/
        lucBuffer[3] = 2;                   /*命令段总长度2*/
        lucBuffer[4] = 0x35;
        lucBuffer[5] = 0x00;                /*命令字0x3500*/


        lucBuffer_Crc[0]     = 0x55;
        lucBuffer_Crc[1]     = 0xAA;
        lucBuffer_Crc[2]     = 0x07;
        lucBuffer_Crc[3]     = 0x31;
        memcpy(lucBuffer_Crc + 4,lucBuffer + 2,4);
        lulCRC = CRC32_Calculate(lucBuffer_Crc,8);

        lucBuffer[6]      = lulCRC >> 24;
        lucBuffer[7]      = lulCRC >> 16;
        lucBuffer[8]      = lulCRC >> 8;
        lucBuffer[9]      = lulCRC;
        lucBuffer[10]     = 0xF0;

        for(n = 0; n < 2; n++)
        {
            lxCanTxData.id_type     = CAN_ID_STANDARD;
            lxCanTxData.frame_type  = CAN_TFT_DATA;
            lxCanTxData.standard_id = 0x731;
            if(n < 1)
            {
                lxCanTxData.dlc     = 8;
            }
            else
            {
                lxCanTxData.dlc     = 3;
            }
            lxCanTxData.data[0]     = lucBuffer[n * 8 + 0];
            lxCanTxData.data[1]     = lucBuffer[n * 8 + 1];
            lxCanTxData.data[2]     = lucBuffer[n * 8 + 2];
            lxCanTxData.data[3]     = lucBuffer[n * 8 + 3];
            lxCanTxData.data[4]     = lucBuffer[n * 8 + 4];
            lxCanTxData.data[5]     = lucBuffer[n * 8 + 5];
            lxCanTxData.data[6]     = lucBuffer[n * 8 + 6];
            lxCanTxData.data[7]     = lucBuffer[n * 8 + 7];
            /*放入队列*/
            MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxData,sizeof(can_tx_message_type),&lxState);
        }
        break;
    }
    case 0x3605:
    {
        memset(lucBuffer,0,80);
        memset(lucBuffer_Crc,0,80);

        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x16;                /*写命令*/
        lucBuffer[3] = 7;                   /*命令段总长度7*/
        lucBuffer[4] = 0x36;
        lucBuffer[5] = 0x05;                /*命令字0x3605*/
        lucBuffer[6] = 'C';
        lucBuffer[7] = 'L';
        lucBuffer[8] = 'E';
        lucBuffer[9] = 'A';
        lucBuffer[10] = 'R';

        lucBuffer_Crc[0]     = 0x55;
        lucBuffer_Crc[1]     = 0xAA;
        lucBuffer_Crc[2]     = 0x07;
        lucBuffer_Crc[3]     = 0x31;
        memcpy(lucBuffer_Crc + 4,lucBuffer + 2,9);
        lulCRC = CRC32_Calculate(lucBuffer_Crc,13);

        lucBuffer[11]      = lulCRC >> 24;
        lucBuffer[12]      = lulCRC >> 16;
        lucBuffer[13]      = lulCRC >> 8;
        lucBuffer[14]      = lulCRC;
        lucBuffer[15]      = 0xF0;

        for(n = 0; n < 2; n++)
        {
            lxCanTxData.id_type     = CAN_ID_STANDARD;
            lxCanTxData.frame_type  = CAN_TFT_DATA;
            lxCanTxData.standard_id = 0x731;
            if(n < 1)
            {
                lxCanTxData.dlc     = 8;
            }
            else
            {
                lxCanTxData.dlc     = 8;
            }
            lxCanTxData.data[0]     = lucBuffer[n * 8 + 0];
            lxCanTxData.data[1]     = lucBuffer[n * 8 + 1];
            lxCanTxData.data[2]     = lucBuffer[n * 8 + 2];
            lxCanTxData.data[3]     = lucBuffer[n * 8 + 3];
            lxCanTxData.data[4]     = lucBuffer[n * 8 + 4];
            lxCanTxData.data[5]     = lucBuffer[n * 8 + 5];
            lxCanTxData.data[6]     = lucBuffer[n * 8 + 6];
            lxCanTxData.data[7]     = lucBuffer[n * 8 + 7];
            /*放入队列*/
            MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxData,sizeof(can_tx_message_type),&lxState);
        }
        break;
    }
    case 0x1008:
    {
        memset(lucBuffer,0,80);
        memset(lucBuffer_Crc,0,80);

        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x0C;                /*广播命令*/
        lucBuffer[3] = 10;                  /*命令段总长度10*/
        lucBuffer[4] = 0x10;
        lucBuffer[5] = 0x08;                /*命令字0x1008*/
        lucBuffer[6] = 'S';
        lucBuffer[7] = 'H';
        lucBuffer[8] = 'U';
        lucBuffer[9] = 'T';
        lucBuffer[10] = 'D';
        lucBuffer[11] = 'O';
        lucBuffer[12] = 'W';
        lucBuffer[13] = 'N';

        lucBuffer_Crc[0]     = 0x55;
        lucBuffer_Crc[1]     = 0xAA;
        lucBuffer_Crc[2]     = 0x08;
        lucBuffer_Crc[3]     = 0x10;
        memcpy(lucBuffer_Crc + 4,lucBuffer + 2,12);
        lulCRC = CRC32_Calculate(lucBuffer_Crc,16);

        lucBuffer[14]      = lulCRC >> 24;
        lucBuffer[15]      = lulCRC >> 16;
        lucBuffer[16]      = lulCRC >> 8;
        lucBuffer[17]      = lulCRC;
        lucBuffer[18]      = 0xF0;

        for(n = 0; n < 3; n++)
        {
            lxCanTxData.id_type     = CAN_ID_STANDARD;
            lxCanTxData.frame_type  = CAN_TFT_DATA;
            lxCanTxData.standard_id = 0x730;
            if(n < 2)
            {
                lxCanTxData.dlc     = 8;
            }
            else
            {
                lxCanTxData.dlc     = 3;
            }
            lxCanTxData.data[0]     = lucBuffer[n * 8 + 0];
            lxCanTxData.data[1]     = lucBuffer[n * 8 + 1];
            lxCanTxData.data[2]     = lucBuffer[n * 8 + 2];
            lxCanTxData.data[3]     = lucBuffer[n * 8 + 3];
            lxCanTxData.data[4]     = lucBuffer[n * 8 + 4];
            lxCanTxData.data[5]     = lucBuffer[n * 8 + 5];
            lxCanTxData.data[6]     = lucBuffer[n * 8 + 6];
            lxCanTxData.data[7]     = lucBuffer[n * 8 + 7];
            /*放入队列*/
            MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxData,sizeof(can_tx_message_type),&lxState);
        }
        break;
    }
    case 0x3A02:
    {
        memset(lucBuffer,0,80);
        memset(lucBuffer_Crc,0,80);

        lucBuffer[0] = 0x55;
        lucBuffer[1] = 0xAA;
        lucBuffer[2] = 0x0C;                /*广播命令*/
        lucBuffer[3] = 4;                   /*命令段总长度4*/
        lucBuffer[4] = 0x3A;
        lucBuffer[5] = 0x02;                /*命令字0x3A02*/
        lucBuffer[6] = 0;                   /*预留，填充0*/
        lucBuffer[7] = gxBikeInfo.Display.Button;   /*按键状态值*/


        lucBuffer_Crc[0]     = 0x55;
        lucBuffer_Crc[1]     = 0xAA;
        lucBuffer_Crc[2]     = 0x07;
        lucBuffer_Crc[3]     = 0x31;
        memcpy(lucBuffer_Crc + 4,lucBuffer + 2,6);
        lulCRC = CRC32_Calculate(lucBuffer_Crc,10);

        lucBuffer[8]      = lulCRC >> 24;
        lucBuffer[9]      = lulCRC >> 16;
        lucBuffer[10]      = lulCRC >> 8;
        lucBuffer[11]      = lulCRC;
        lucBuffer[12]      = 0xF0;

        for(n = 0; n < 2; n++)
        {
            lxCanTxData.id_type     = CAN_ID_STANDARD;
            lxCanTxData.frame_type  = CAN_TFT_DATA;
            lxCanTxData.standard_id = 0x731;
            if(n < 1)
            {
                lxCanTxData.dlc     = 8;
            }
            else
            {
                lxCanTxData.dlc     = 5;
            }
            lxCanTxData.data[0]     = lucBuffer[n * 8 + 0];
            lxCanTxData.data[1]     = lucBuffer[n * 8 + 1];
            lxCanTxData.data[2]     = lucBuffer[n * 8 + 2];
            lxCanTxData.data[3]     = lucBuffer[n * 8 + 3];
            lxCanTxData.data[4]     = lucBuffer[n * 8 + 4];
            lxCanTxData.data[5]     = lucBuffer[n * 8 + 5];
            lxCanTxData.data[6]     = lucBuffer[n * 8 + 6];
            lxCanTxData.data[7]     = lucBuffer[n * 8 + 7];
            /*放入队列*/
            MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxData,sizeof(can_tx_message_type),&lxState);
        }
        break;
    }
    }


}



/******************************************************************************
** 功  能：仪表设置限速值
** 参  数：LimitSpeed-限速值，0.1km/h
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_LimitSpeed(uint16_t LimitSpeed)
{

}



/******************************************************************************
** 功  能：设置仪表开机标志位
** 参  数：State-仪表状态。0-关闭，1-打开
** 返回值：无
** 备  注：安乃达CAN协议，18FD0128用
******************************************************************************/
void vPROTOCOL_Set_Power(uint8_t State)
{

}



/******************************************************************************
** 功  能：设置按键状态
** 参  数：KeyValue-按键值
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Button(uint8_t KeyValue)
{
    static uint8_t lucLastKeyValue = 0;

    if(lucLastKeyValue != KeyValue)
    {
        lucLastKeyValue = KeyValue;

        /*UP键*/
        if(KeyValue & 0x01)
        {
            gxBikeInfo.Display.Button |= 0x10;
        }
        else
        {
            gxBikeInfo.Display.Button &= 0xEF;
        }

        /*DOWN键*/
        if(KeyValue & 0x04)
        {
            gxBikeInfo.Display.Button |= 0x08;
        }
        else
        {
            gxBikeInfo.Display.Button &= 0xF7;
        }

        /*POWER键*/
        if(KeyValue & 0x08)
        {
            gxBikeInfo.Display.Button |= 0x20;
        }
        else
        {
            gxBikeInfo.Display.Button &= 0xDF;
        }

        /*MODE键*/
        if(KeyValue & 0x02)
        {
            gxBikeInfo.Display.Button |= 0x01;
        }
        else
        {
            gxBikeInfo.Display.Button &= 0xFE;
        }

        vCan_Send_DisplayMessage(0x0731,0x3A02,&gxBikeInfo);    /*按键状态和上次有变化时，发送一次按键状态*/
    }

}

/******************************************************************************
** 功  能：设置大灯状态
** 参  数：State-大灯状态。0-关闭，1-打开
** 返回值：无
** 备  注：所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Lamp(uint8_t State)
{
    gxBikeInfo.Display.Lamp = 0xF0 | State;     /*灯状态*/
}

/******************************************************************************
** 功  能：发送关机指令
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_PowerOff(void)
{
    gucRequestPowerOff = 1;     /*置位关机标志*/
}



/******************************************************************************
** 功  能：设置档位
** 参  数：Pas-档位值，最大为9，最小为-1,-1表示助推档
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Pas(int8_t Pas)
{
    /*此处对于安乃达协议的助推尚有疑问，是否这样处理，需要控制器验证*/
    if(Pas > -1 && Pas < 6)
    {
        if(Pas == 5)
        {
            gxBikeInfo.Display.Pas = 0x33;      /*5档发0x33*/
        }
        else
        {
            gxBikeInfo.Display.Pas = Pas;       /*5挡位的话，按照实际挡位发送*/
        }
    }
    else
    {
        gxBikeInfo.Display.Pas    = 0x22;  /*推行挡位*/
    }
}



/******************************************************************************
** 功  能：设置轮径调整值
** 参  数：Adjust-轮径调整值，范围±10cm
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_WheelLength_Adjust(int8_t Adjust)
{
    gxBikeInfo.Display.WheelLength_Adjust = Adjust;
    vCan_Send_DisplayMessage(0x0731,0x3408,&gxBikeInfo);
}



/******************************************************************************
** 功  能：设置清Trip
** 参  数：State-是否清Trip，0-不清，1-清Trip
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_ClearTrip(uint8_t State)
{
    if(State)
    {
        vCan_Send_DisplayMessage(0x0731,0x3605,&gxBikeInfo);
        vCan_Send_DisplayMessage(0x0731,0x3605,&gxBikeInfo);
        vCan_Send_DisplayMessage(0x0731,0x3605,&gxBikeInfo);
    }
}

/******************************************************************************
** 功  能：获取电压值
** 参  数：无
** 返回值：实际电压值的10倍。比如实际电流36.0V，返回360
** 备  注：
******************************************************************************/
uint16_t    usPROTOCOL_Get_Voltage(void)
{
    return gxBikeInfo.MCU.Voltage / 100;
}

/******************************************************************************
** 功  能：获取当前电流值
** 参  数：无
** 返回值：实际电流值的10倍。比如实际电流12.3A，返回123
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Current(void)
{
    return gxBikeInfo.MCU.Current / 100;
}

/******************************************************************************
** 功  能：获取电池容量
** 参  数：无
** 返回值：-1表示未获取到电池容量，电池容量，0-100%
** 备  注：
******************************************************************************/
int8_t cPROTOCOL_Get_Soc(void)
{
    /*优先返回电池发送的SOC，其次返回控制器发送的SOC*/
    if(cPROTOCOL_Get_BMS_SOC() > 0)
    {
        return cPROTOCOL_Get_BMS_SOC();
    }
    else
    {
        return gxBikeInfo.MCU.Soc;
    }
}


/******************************************************************************
** 功  能：获取当前车速
** 参  数：无
** 返回值：实际车速*10.比如返回120，实际车速即12.0Km/h
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed(void)
{
    return gxBikeInfo.MCU.Speed;
}

/******************************************************************************
** 功  能：获取错误代码
** 参  数：无
** 返回值：十进制的错误代码
** 备  注：通信超时错误代码是70
******************************************************************************/
uint8_t ucPROTOCOL_Get_Errcode(void)
{
    uint8_t MCU_ErrorCodeTab[] = {10,11,12,13,14,16,17,18,22,15,19,21,20,27,23,24,25,26,28,29,30,31,32};
    uint8_t BMS_ErrorCodeTab[] = {41,42,43,44,45,46,47,48,49};
    uint8_t n;
    if(gxBikeInfo.ErrCode > 0)
    {
        return gxBikeInfo.ErrCode;
    }
    else
    {
        /*按位对MCU故障码进行比对，有对应故障码时输出对应的故障码*/
        for(n = 0; n < 23; n++)
        {
            if((gxBikeInfo.MCU.ErrorCode & (0x00000001 << n)) != 0)
            {
                break;
            }
        }
        if(n < 23)
        {
            return MCU_ErrorCodeTab[n];
        }
        else
        {
            /*没有查到MCU的故障吗，继续对BMS的故障码进行比对*/
            for(n = 0; n < 9; n++)
            {
                if((gxBikeInfo.Battery.ErrorCode & (0x00010000 << n)) != 0)
                {
                    break;
                }
            }
            if(n < 9)
            {
                return BMS_ErrorCodeTab[n];
            }
            else
            {
                return 0;
            }
        }
    }

}

/******************************************************************************
** 功  能：获取TRIP里程
** 参  数：无
** 返回值：TRIP值，0.1Km
** 备  注：
******************************************************************************/
uint32_t ulPROTOCOL_Get_Trip(void)
{
    return gxBikeInfo.MCU.Trip;
}


/******************************************************************************
** 功  能：获取轮径长度（cm）
** 参  数：无
** 返回值：轮径长度，单位cm
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Wheel_Lenght(void)
{
    return gxBikeInfo.MCU.WheelLength_Base;
}

/******************************************************************************
** 功  能：获取轮径长度调整值（cm）
** 参  数：无
** 返回值：轮径长度调整值，单位cm
** 备  注：
******************************************************************************/
int8_t cPROTOCOL_Get_Wheel_Lenght_Adjust(void)
{
    return gxBikeInfo.MCU.WheelLength_Adjust;
}

/******************************************************************************
** 功  能：获取限速值
** 参  数：无
** 返回值：限速值，1km/h
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed_Limit(void)
{
    return gxBikeInfo.MCU.SpeedLimit;
}

/******************************************************************************
** 功  能：获取ODO里程
** 参  数：无
** 返回值：ODO值，0.1Km
** 备  注：
******************************************************************************/
uint32_t ulPROTOCOL_Get_Odo(void)
{
    return gxBikeInfo.MCU.ODO;
}

/******************************************************************************
** 功  能：获取剩余里程
** 参  数：无
** 返回值：剩余里程，Range值，1Km
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Range(void)
{
    return gxBikeInfo.MCU.Range;
}




/******************************************************************************
** 功  能：获取骑行时间
** 参  数：无
** 返回值：骑行时间，单位：min
** 备  注：
******************************************************************************/
uint32_t usPROTOCOL_Get_Riding_Time(void)
{
    return gxBikeInfo.MCU.Trip_Time;
}

/******************************************************************************
** 功  能：获取电机功率
** 参  数：无
** 返回值：电机功率，单位：1W
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Motor_Power(void)
{
    return gxBikeInfo.MCU.Power;
}



/******************************************************************************
** 功  能：获取BMS电压
** 参  数：无
** 返回值：BMS电压值，0.1V
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_Voltage(void)
{
    return gxBikeInfo.Battery.Voltage / 100;
}

/******************************************************************************
** 功  能：获取BMS电流
** 参  数：无
** 返回值：BMS电流值，0.1A
** 备  注：
******************************************************************************/
int16_t sPROTOCOL_Get_BMS_Current(void)
{
    return gxBikeInfo.Battery.Current / 100;
}

/******************************************************************************
** 功  能：获取BMS的SOH
** 参  数：无
** 返回值：SOH，1%精度
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_SOH(void)
{
    return gxBikeInfo.Battery.Soh;
}

/******************************************************************************
** 功  能：获取BMS的SOC
** 参  数：无
** 返回值：SOC，1%精度
** 备  注：
******************************************************************************/
int8_t cPROTOCOL_Get_BMS_SOC(void)
{
    return gxBikeInfo.Battery.Soc;
}

/******************************************************************************
** 功  能：获取BMS的剩余容量
** 参  数：无
** 返回值：剩余容量值，1mAh
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_ResCap(void)
{
    return gxBikeInfo.Battery.ResCap;
}


/******************************************************************************
** 功  能：获取对应电芯的电压值
** 参  数：CellNum-电芯序号，从1开始，1-16
** 返回值：电芯电压，mv
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_Cell_Voltage(uint8_t CellNum)
{
    if(CellNum > 16)
    {
        CellNum = 16;
    }
    return gxBikeInfo.Battery.CellVoltage[CellNum];
}



/******************************************************************************
** 功  能：工厂指令的解析
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Factory_Command(can_rx_message_type *pCanRxMsg)
{
    uint16_t lusResponse;

    switch(pCanRxMsg->extended_id)
    {
    case 0x1F18016E:/*校准光感，返回0x03F8016E*/
    {
        lusResponse = vPhotoDiode_Calibration();
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F18025D:/*校准电压，返回0x03F8025D*/
    {
        lusResponse = vVoltage_Calibration();
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F180371:/*校准时间，返回0x03F80371*/
    {
        vDateTime_Calibration(pCanRxMsg->data[3],pCanRxMsg->data[4],pCanRxMsg->data[5],pCanRxMsg->data[0],pCanRxMsg->data[1],pCanRxMsg->data[2]);
        lusResponse = 1234;
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F18048E:/*清ODO，返回0x03F8048E*/
    {
        vClear_ODO();
        lusResponse = 5678;
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    }
}

/******************************************************************************
** 功  能：工厂指令的返回
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
static void vPROTOCOL_Factory_Response(uint32_t Cmd,uint16_t Data)
{
    can_tx_message_type    lxCanTxMessage;

    lxCanTxMessage.id_type      = CAN_ID_EXTENDED;      /*扩展帧*/
    lxCanTxMessage.frame_type   = CAN_TFT_DATA;         /*数据帧*/
    lxCanTxMessage.dlc          = 2;                    /*数据长度*/
    lxCanTxMessage.extended_id  = 0x03F80000 | (Cmd & 0x0000FFFF);
    lxCanTxMessage.data[0]      = Data >> 8;
    lxCanTxMessage.data[1]      = (uint8_t)Data;

    /*调用发送函数进行发送*/
    can_message_transmit(CAN1,&lxCanTxMessage);
}

/******************************************************************************
** 功  能：复位通信超时计数变量
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_ResetCommunicationOverTime(void)
{
    gulCommunicationCnt = 0;        /*复位通信超时计数*/
    if(gxBikeInfo.ErrCode == 70)
    {
        gxBikeInfo.ErrCode = 0;
    }
}


/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_PowerOn(void)
{
    gxBikeInfo.Display.IdleTime   = gtParam.Idle_Time;
    gxBikeInfo.Display.StartType  = 2;
    gxBikeInfo.Display.AssistType = 1;
    vPROTOCOL_Set_Pas(0);                                           /*开机LOGO界面发0档*/

}

/******************************************************************************
** 功  能：退出设置时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_ExitSetting(void)
{
    gxBikeInfo.Display.IdleTime = gtParam.Idle_Time;        /*更新自动关机时间*/
    vCan_Send_DisplayMessage(0x0731,0x3408,&gxBikeInfo);
    vCan_Send_DisplayMessage(0x0731,0x3408,&gxBikeInfo);
    vCan_Send_DisplayMessage(0x0731,0x3408,&gxBikeInfo);
}


